package com.example.security.filter;

import com.example.base.dto.TokenUserDTO;
import com.example.base.utils.JWTUtil;
import com.example.base.utils.RedisUtil;
import com.example.security.assembly.UserPostLoginAuthenticationToken;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * 将token 解析成为 UserPostLoginAuthenticationToken
 * 然后设置到请求上下文
 * 后续过滤器将不会再执行
 */
@Slf4j
@Component
public class JWTAuthenticationFilter extends OncePerRequestFilter {

    public static final String TOKEN_CACHE_PRE = "user:token:";

    //token默认过期时间 一个小时
    public static final Long TIME_OUT = 60L;

    /**
     * 获取token 过滤器
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //如果不为空 直接不走这里了
        if (Objects.nonNull(authentication)){
            filterChain.doFilter(request, response);
            return;
        }
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StringUtils.isBlank(token)){
            filterChain.doFilter(request, response);
            return;
        }
        //根据token 解析出用户信息
        TokenUserDTO tokenUser = JWTUtil.parseToken(token);
        //判断token 是否已经过期
        boolean flag = tokenValidOrNot(token, tokenUser.getUserId());
        if (flag){
            //过期请求继续转发
            filterChain.doFilter(request, response);
            return;
        }
        //没过期
        authentication = UserPostLoginAuthenticationToken.authenticated(tokenUser);
        //设置到请求上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
    }

    /**
     * 判断token 是否过期
     * @param token
     * @param userId
     * @return
     */
    public boolean tokenValidOrNot(String token, Long userId){
        boolean flag = JWTUtil.isExpired(token);
        if (flag){
            //过期需要判断 redis 是否也同时过期
            flag = RedisUtil.expire(TOKEN_CACHE_PRE + userId);
        }
        //没有过期 刷新token 有效期
        if (!flag){
            flag = !RedisUtil.refreshKey(TOKEN_CACHE_PRE + userId, TIME_OUT);
        }
        return flag;
    }
}
